/*
 * @(#)WorkflowAjaxProcessor.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.core;

import java.sql.Connection;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.PermissionManager;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.Utility;
import com.dcivision.user.bean.UserGroup;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.UserGroupDAObject;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.user.dao.UserRoleDAObject;
import com.dcivision.workflow.bean.WorkflowGroup;
import com.dcivision.workflow.bean.WorkflowRecord;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.dao.WorkflowGroupDAObject;
import com.dcivision.workflow.dao.WorkflowRecordDAObject;
import com.dcivision.workflow.dao.WorkflowStepDAObject;

/**
 * <p> Class Name: WorkflowAjaxProcessor</p>
 * <p> Decription: This class is responsible for workflow use the ajax to handle any logic.</p> *
 * 
 *
 * @author          Tony Chen
 * @company         DCIVision Limited
 * @creation date   25/10/2005
 * @version         $Revision: 1.18.2.7 $
 */

public class WorkflowAjaxProcessor {
  protected Log log = LogFactory.getLog(this.getClass().getName());
  
  /**
   * service for dwr-client request for a workflowRecord info by workflowCode.
   * 
   * @param workflowCode
   *          workflowRecord's Code
   * @return workflowRecord info translated to response string append all elements
   */
  public String getWorkflowRecordValue(String workflowCode) {
    StringBuffer responseWorkflowRecord = new StringBuffer();
    Connection conn = null;
    try {
      conn = DataSourceFactory.getConnection();
      WorkflowRecordDAObject workflowRecordDAO = new WorkflowRecordDAObject(
          this.getSessionContainer(), conn);
      WorkflowRecord record = (WorkflowRecord) workflowRecordDAO
          .getEffectiveWorkflowRecordByWorkflowCode(workflowCode);
      if (!Utility.isEmpty(record)) {
        Timestamp startDate = record.getStartDate();
        Timestamp endDate = record.getEndDate();
        responseWorkflowRecord.append("workflow.label.workflow_version:"
            + record.getWorkflowVersion() + "|");
        responseWorkflowRecord.append("workflow.label.effective_period:"
            + (startDate == null ? "" : TextUtility.getDateFormat().format(
                startDate)) + "|");
        responseWorkflowRecord.append("common.label.period_to:"
            + (endDate == null ? "" : TextUtility.getDateFormat().format(
                endDate)) + "|");
        responseWorkflowRecord.append("workflow.label.description:"
            + record.getDescription() + "|");
      }
    } catch (Exception e) {
      log.error(e);
    } finally {
      try {
        conn.close();
      } catch (Exception ignore) {
      } finally {
        conn = null;
      }
    }
    return responseWorkflowRecord.toString();
  }
  
  public String getWorkflowRecord(String categoryID, String groupID,
        String language, String sUserRecordID) {
    StringBuffer workflowRecordSb = new StringBuffer();
    Integer wfCategoryID = null;
    Integer wfGroupID = null;
    Integer userRecordID = new Integer(0);
    
    Locale locale = Utility.getLocaleByString(language);
    
    if ( !Utility.isEmpty(categoryID) ) {
      wfCategoryID = new Integer(categoryID);
    }
    
    if ( !Utility.isEmpty(groupID) ) {
      wfGroupID = new Integer(groupID);
    }

    if (!Utility.isEmpty(sUserRecordID)) {
      userRecordID = new Integer(sUserRecordID);
    }
    
    Connection dbConn = null;    
    try {
      dbConn = DataSourceFactory.getConnection();
      WorkflowRecordDAObject wfRecordDAO = new WorkflowRecordDAObject(this.getSessionContainer(), dbConn);
      SessionContainer sessionCon = this.getSessionContainer();
      UserRecord tempUserRecord = new UserRecord();
      tempUserRecord.setID(userRecordID);
      sessionCon.setUserRecord(tempUserRecord);
      PermissionManager permissionManager = new PermissionManager(sessionCon);
      UserRoleDAObject userRoleDAO = new UserRoleDAObject(sessionCon, dbConn);
      UserGroupDAObject userGroupDAO = new UserGroupDAObject(sessionCon, dbConn);
      List userRoleList = userRoleDAO.getListByUserRecordID(userRecordID);
      List userGroupList = userGroupDAO.getListByUserRecordIDGroupType(userRecordID, UserGroup.GROUP_TYPE_PUBLIC);
      permissionManager.setUserRoles(userRoleList);
      permissionManager.setUserGroups(userGroupList);
      List wfRecordList = wfRecordDAO.getListByWorkflowGroupIDWorkflowCategoryID(wfGroupID, wfCategoryID);
      workflowRecordSb.append("{");
      workflowRecordSb.append("'':'" + MessageResourcesFactory.getMessage(locale, "common.options.select_menu.select_one") + "'"); 

      for (int i = 0; i < wfRecordList.size(); i++) {
        WorkflowRecord wfRecord = (WorkflowRecord)wfRecordList.get(i);
        if (permissionManager.hasAccessRight(dbConn, GlobalConstant.OBJECT_TYPE_WORKFLOW,
              wfRecord.getWorkflowGroupID(), "M")) {

          workflowRecordSb.append(",");
          workflowRecordSb.append("'" + wfRecord.getID().toString() + "':" );
          // falcon_add_start
          String workflowCode=TextUtility.replaceString(wfRecord.getWorkflowCode(), "'", "\\'");
          String description=TextUtility.replaceString(wfRecord.getDescription(), "'", "\\'"); 
          String workflowVersion=TextUtility.replaceString(wfRecord.getWorkflowVersion(), "'", "\\'");
          // falcon_add_end
          if (Utility.isEmpty(wfRecord.getDescription())) {
            workflowRecordSb.append("'" + workflowCode + " [" + workflowVersion + "]" + "'" );
          } else {
            if(wfRecord.getDescription().length() > 16){
              workflowRecordSb.append("'" + workflowCode + " - " + description.substring(0,16) + "... [" + workflowVersion + "]" + "'" );
            } else {
              workflowRecordSb.append("'" + workflowCode + " - " + description + " [" + workflowVersion + "]" + "'" );
            }
          }
        }
      }
      workflowRecordSb.append("}");
    } catch (ApplicationException appEx) {
      log.debug(" Application Exception :", appEx);
      log.error(appEx);
    } catch (Exception e) {     
      log.error(e);
    } finally {
      try { dbConn.close(); } catch (Exception ignore) {} finally { dbConn = null; }
    }       
    
    return workflowRecordSb.toString();
  }
  
    
  
  /**
   * get Session Container
   * @return
   */
  public SessionContainer getSessionContainer() {
    SessionContainer sessionCon = new SessionContainer();
   
    UserRecord tmpUserRecord = new UserRecord();
    tmpUserRecord.setID(new Integer(0));
    sessionCon.setUserRecord(tmpUserRecord);
    sessionCon.setUserIPAddress("127.0.0.1");
    
    return sessionCon;
  }
  /**
   * get the sessionContainer from session
   * @param session
   * @return
   */
  public SessionContainer getSessionContainer(HttpSession session){
    SessionContainer sessionCon=(SessionContainer)session.getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    if(sessionCon==null){
      sessionCon = getSessionContainer();
    }
    return sessionCon;
  }
  
  /**
   * Account the value of user can execute current step and compare to the given rule,
   * return a warning message if the result value is less than the rule, otherwise return
   * an empty text value instead.
   * 
   * @param allPermission all of the permission definitions in a string
   * @param rule the given rule
   * @return return a warning message if the result value is less than the rule, otherwise return
   *                an empty text value instead.
   */
  public String checkWorkflowStepRule(String allPermission, String rule) {
    
    if (Utility.isEmpty(allPermission) || Utility.isEmpty(rule)) {
      // return "ERROR PARAMETER";
      return ""; // This should validate in client.
    }
    
    int ruleCount = 1;
    
    if ("*".equals(rule)) {
      rule = "1"; // When rule value is "*", one count of user can execute is need at least.
    }
    
    try {
      ruleCount = TextUtility.parseInteger(rule);
    } catch (Exception e) {
      return "ERROR RULE VALUE"; // This should validate in client, rule must be int value or "*".
    }
    
    Connection dbConn = null;
    try {
      dbConn = DataSourceFactory.getConnection();
      UserRecordDAObject userDao = new UserRecordDAObject(this.getSessionContainer(), dbConn);
      int userCountCanExecute=userDao.getUserCountCanExecute(allPermission); 
      
      if(userCountCanExecute < ruleCount){
        return ""+userCountCanExecute;
      }
      
      return "";
    } catch (ApplicationException appEx) {
      log.debug(" Application Exception :", appEx);
      log.error(appEx);
      return appEx.toString();
    } catch (Exception e) {
      log.error(e);
      return e.toString();
    } finally {
      try {
        dbConn.close();
      } catch (Exception ignore) {
      } finally {
        dbConn = null;
      }
    }
  }
  
  /**
   * return "Y" means can move subsequent steps "N" means not
   * @param currentStepId
   * @param ParentStepId
   * @return
   */
  public String checkIfCanMoveSubsequentSteps(Integer parentStepID,Integer currentStepID){
    //if parentStepId contained in the subsequent Steps return "N"
    Connection dbConn = null;    
    try {
      dbConn = DataSourceFactory.getConnection();
      WorkflowRetrievalManager workflowRetrievalMag = new WorkflowRetrievalManager(this.getSessionContainer(),dbConn);
      if(workflowRetrievalMag.checkIfSubSequentStepsContainedCurrentStep(parentStepID, currentStepID)) {
        return "N";
      } else {
        return "Y";
      }
    }catch (Exception ex) {
      
    } finally {
      try {
        dbConn.close();
      } catch (Exception ignore) {
      } finally {
        dbConn = null;
      }
    }
    return "N";
  }
  
  public String checkIfCanMerged(Integer parentStepID,Integer currentStepID,Integer[] steps){
    Connection dbConn = null;    
    try {
      dbConn = DataSourceFactory.getConnection();
      WorkflowRetrievalManager workflowRetrievalMag = new WorkflowRetrievalManager(this.getSessionContainer(),dbConn);
      //check subStep can not contains currentStep
      if(workflowRetrievalMag.checkIfSubSequentStepsContainedCurrentStep(parentStepID, currentStepID)) {
        return "N";
      }
      
      //check the Steps
      if(Utility.isEmpty(steps)) {
        return "Y";
      }
      
      //check if currentStep and any element of Steps in the same branch of parrallel step
      if(workflowRetrievalMag.checkIfOneBranchOfParrallelContainsCurrentSteps(currentStepID,steps)){
        return "N";
      }
      //check other
      
      //return result 'Y' if pass the check
        return "Y";
      
    }catch (Exception ex) {
      
    } finally {
      try {
        dbConn.close();
      } catch (Exception ignore) {
      } finally {
        dbConn = null;
      }
    }
    return "N";
  }
  
  public String getConnectStepOption(Integer workflowStepID,boolean bSubSteps){
    Connection dbConn = null;    
    try {
      dbConn = DataSourceFactory.getConnection();
      WorkflowRetrievalManager workflowRetrievalMag = new WorkflowRetrievalManager(this.getSessionContainer(),dbConn);
      List resultList=null;
      StringBuffer result = new StringBuffer();
      
      if(bSubSteps){
        resultList=workflowRetrievalMag.retrieveWorkflowStepToEndStepArray(workflowStepID);
      }else{
        resultList=workflowRetrievalMag.retrieveWorkflowStepArray(workflowStepID,null);
      }
      log.debug("Size:"+resultList.size());
      for(int i=0;i<resultList.size();i++){
        String[] option = (String[])resultList.get(i);
        result.append("<option value=\""+option[1]+"\">");
        result.append(option[0]);
        result.append("</option>");
      }
      return result.toString();
    }catch (Exception ex) {
      
    } finally {
      try {
        dbConn.close();
      } catch (Exception ignore) {
      } finally {
        dbConn = null;
      }
    }
    return "<option>Default</option>";
  }
  
  public String checkIfCanChangeTheCategoryByWorkflowRecordIDAndCategoryID(Integer workflowRecordID,String categoryID){
    Connection dbConn = null;  
    if(Utility.isEmpty(workflowRecordID)){
      return "Y";
    }
    try {
      dbConn = DataSourceFactory.getConnection();
      WorkflowStepManager stepManager = new WorkflowStepManager(this.getSessionContainer(),dbConn);
      WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(this.getSessionContainer(),dbConn);
      List stepList = stepDAO.getListByWorkflowRecordID(workflowRecordID);
      String[][] stepTypes=stepManager.retrieveWorkflowStepTypes(categoryID);
      
      List stepTypeList = new ArrayList();
      for(int j=0;j<stepTypes.length;j++){
        stepTypeList.add(stepTypes[j][1]);
      }
      
      for(int i=0;i<stepList.size();i++){
        WorkflowStep step = (WorkflowStep)stepList.get(i);
        if(WorkflowStep.ACTION_TYPE_SUBMIT.equals(step.getActionType())||WorkflowStep.ACTION_TYPE_END.equals(step.getActionType())){
          //if startWorkflowStep and EndStep not check
          continue;
        }
        if(!stepTypeList.contains(step.getActionType())){
          //this category do not contains this special actionType
          return "N";
        }
        }
       }catch (Exception ex) {
          return "N";
       } finally {
          try {
                dbConn.close();
              } catch (Exception ignore) {
              } finally {
                         dbConn = null;
                        }
              }
     return "Y";
  }
  
  public String checkIfCanLoopBackCurrentStep(Integer stepID,Integer currentStepID,Integer parentID){
    //if have the same parentStep then can not loopback this step
    Connection dbConn = null; 
    Integer[] childStepIDs = new Integer[2];
    if(Utility.isEmpty(stepID)||Utility.isEmpty(currentStepID)){
      return "N";
    }
    childStepIDs[0] = stepID;
    childStepIDs[1] = currentStepID;
    
    try {
      dbConn = DataSourceFactory.getConnection();
      WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(this.getSessionContainer(),dbConn);
      List stepList = stepDAO.getTheParentStepListByChildStpIDs(childStepIDs);
      if(Utility.isEmpty(stepList)||stepList.size()<=0){
        //have no common parent_step
        return "Y";
      }else{
      for(Iterator it=stepList.iterator();it.hasNext();){
        WorkflowStep step = (WorkflowStep)it.next();
        if(step.getID().equals(parentID)){
          //they are sbling
          return "N";
        }
      }
        return "Y";
      }
    }catch (Exception ex) {
      return "N";
    } finally {
       try {
             dbConn.close();
           } catch (Exception ignore) {
           } finally {
                      dbConn = null;
                     }
           }
  }
  
  public String checkIfCanSubmitTheWorkflowRecord(HttpSession session,Integer workflowRecordID){
    Connection dbConn = null; 
    try {
      dbConn = DataSourceFactory.getConnection();
      WorkflowProgressActionTakerCheckerManager progressCheckManager = new WorkflowProgressActionTakerCheckerManager(this.getSessionContainer(session),dbConn);
      WorkflowRecordDAObject recordObject = new WorkflowRecordDAObject(this.getSessionContainer(session),dbConn);
      WorkflowRecord record = (WorkflowRecord)recordObject.getObjectByID(workflowRecordID);
      if(Utility.isEmpty(record.getInterruptWorkflowRecordID())){
        //did not start interrupt workflow
        return "Y";
      }
      
      WorkflowRecord interruptRecord = (WorkflowRecord)recordObject.getObjectByID(record.getInterruptWorkflowRecordID());
      if(!Utility.isEmpty(interruptRecord.getEndDate())&&interruptRecord.getEndDate().before(Utility.getCurrentTimestamp())){
        throw new ApplicationException("errors.calendar.recurring_start_date_priorduedate");
      }
      boolean b=progressCheckManager.checkIfThisUserCanSubmitThisWorkflow(record.getInterruptWorkflowRecordID());
      return "Y";
    }catch (ApplicationException e) {
      return MessageResourcesFactory.getMessage(this.getSessionContainer(session).getSessionLocale(),e.getMsgCode());
    } catch (Exception e) {
      return "DB ERROR";
    } finally {
       try {
             dbConn.close();
           } catch (Exception ignore) {
           } finally {
                      dbConn = null;
                     }
           }
  }

  /**
   * get WorkflowGroupID by workflowRecordID.
   * @param sWorkflowRecordID the String of workflowRecordID.
   *        when user checked the "===Select===" option
   *        the sWorkflowRecordID value is ""
   * @return WorkflowGroupID.
   */
  public String getWorkflowGroup(String sWorkflowRecordID) {
    StringBuffer workflowRecordSb = new StringBuffer();
    Integer workflowRecordID = null;

    if ( !Utility.isEmpty(sWorkflowRecordID) ) {
      workflowRecordID = new Integer(sWorkflowRecordID);
      Connection dbConn = null;
      try {
        dbConn = DataSourceFactory.getConnection();
        WorkflowGroupDAObject wfGroupDAO = new WorkflowGroupDAObject(this.getSessionContainer(), dbConn);
        WorkflowGroup workflowGroup = (WorkflowGroup)wfGroupDAO.getByWorkflowRecordID(workflowRecordID);
        if (!Utility.isEmpty(workflowGroup)) {
           workflowRecordSb.append(workflowGroup.getID());
        }
      } catch (ApplicationException appEx) {
        log.debug(" Application Exception :", appEx);
        log.error(appEx);
      } catch (Exception e) {     
        log.error(e);
      } finally {
        try { dbConn.close(); } catch (Exception ignore) {} finally { dbConn = null; }
      }   
    }
    return workflowRecordSb.toString();
  }
}